#!/usr/bin/perl
#
# Copyright (C) 2006 Nikolai Joukov, Avishay Traeger, and Erez Zadok
# Copyright (C) 2006 Stony Brook University
#
# Usage: plot_OP_map.pl -VPLM <cpuspeed>
#   -V use vertical layout for multiple operations
#      (the default is horizontal)
#   -P use seconds as the bottom axis
#   -L use "log" title for the bucket axis
#   -M CPU speed is <cpuspeed> GHz
#

use Getopt::Std; getopts("VPLM:") || die "usage: $0 [-VPL -M <cpuspeed>]\n";

$opt_V = 0 if !defined($opt_V);

$origin_y = 0.02;
$origin_y_step = 0.113;

$sets = 0;
$l = 0;
while (<STDIN>) {
	chop($_);
	s/OP_//g;
	s/_/\\_/g;
	if (!m/^\#/) {
		if (m/^title/) {
			($tmp, $TITLE[$sets]) = split( /=/, $_ );
		} else {
			if (m/^set /) {
				$CUSTOM_CMD[$l] = $_;
		    	} else {
				if (length($_) < 10) {
					$sets++;
					$l = 0;
				} else {
					(@tmp) = split( / /, $_ );
					for (my $b = 0; $b <= $#{@tmp}; $b++) {
						$BUCKETS[$sets][$l][$b] = $tmp[$b];
					}
					$l++;
				}
			}
		}
	}
}
# Handle files with no EOF 
if ($sets == 0) { $sets = 1; }

$min_x = 4;
$min_x = 3 if defined($opt_L);

$max_y = $#{$BUCKETS[0]};
$max_x = $#{$BUCKETS[0][0]};

if ($opt_M && $opt_P) {
	$halfbox = 4.0/($opt_M * 2.0);
} else {
	$halfbox = 0.5;
}

if ($opt_M && $opt_P) {
	$delay_units = "sec";
} else {
	$delay_units = "2^{32} CPU cycles";
}

print <<"END_GNUPLOT";
#!/usr/local/bin/gnuplot

set term push;
set terminal postscript eps enhanced 'Helvetica' 14;

set size 1.0,$max_y*0.3/12.0+0.15+($opt_V*($sets-1)*$max_y*0.3/12.0)
set origin 0.0,0.0
set style fill solid 1.0

set yrange [-$halfbox:$max_y*2.0*$halfbox-$halfbox]
set xrange [$min_x:31+$min_x]
#set noborder
#set border 11
set grid x
set grid y
set multiplot
set xtics 5,5.0
set ytics autofreq
END_GNUPLOT

$opt_R = 1.0; # not supported yet
if (!defined($opt_L)) {
	$X_label_buckets = "Bucket (2^{n-1} <= x < 2^n CPU Cycles)";
} else {
	$X_label_buckets = "\'Bucket number: {/Symbol=14 \353}log_{2}(latency in CPU cycles){/Symbol=14 \373}\'";
	#//$opt_R != 1 ? "":"^{1/$opt_R}"
}
print "set xlabel $X_label_buckets\n" if !$opt_V;

if ($sets > 1) {
	print "set boxwidth ", 1.0/($sets+1.0), "\n";
} else {
	print "set boxwidth ", 1.0, "\n";
}

for (my $s = 0; $s < $sets; $s++) {
	$width = 1.0/$sets;
	$width = 1.0 if $opt_V;
	print "set size ", $width, ",", $max_y * 0.2 / 12.0 + 0.15, "\n";
	if ($opt_V) {
		print "set origin 0.0,", 0.02 + $s * ($max_y * 0.265 / 12.0), "\n";
	} else {
		print "set origin ", $s*$width , ",0.0\n";
	}
	print "set label \'$TITLE[$s]\' at graph ",
		0.2 + 0.79 * $opt_V, ",", 1.2 - 0.35 * $opt_V,
		!$opt_V ? " center" : " right", " font \"Helvetica,16\"\n";
	print "set label \'Elapsed time ($delay_units)\' at graph ",
		-0.08 - 0.05*!$opt_V, ",", 0.5 + $opt_V * $sets/3.0,
		"center rotate font \"Helvetica,14\"\n" if (($opt_V && !$s) || !$opt_V);

	if (!$opt_V || $s == $sets - 1) {
		print "set key graph ", 0.87+0.07*$opt_V, ",1.4\n" ;
		print "set border\n";
		print "set xtics mirror (" if $opt_V;
	} else {
		print "set nokey\n";
		print "set border 11\n";
		print "set xtics nomirror (" if $opt_V;
	}
	if ($opt_V) {
		for ($j = 5; $j < $max_x - 5; $j += 5) {
			print "\"\" ", $j, ",";
		}
		print "\"\" ", $j, ")\n";
	}

	$stretch_y = 2.0 * $halfbox * $max_y / 12.0;
	# X tics and title in buckets
	if ($opt_V && ((!$s && !defined($opt_P)) || ($s == $sets - 1 && defined($opt_P)))) {
		for (my $i = 5.0; $i <= $max_x; $i += 5) {
			# skip the last tic if it may overlap with the legend
			if (($i > $min_x) && (($i < $max_x - 4) || !defined($opt_P) || $sets == 1)) {
				print "set label \'$i\' at graph ", ($i - $min_x)/($max_x - $min_x + 2.0), ",";
				if (defined($opt_P)) {
					print 1 + 0.15/$stretch_y;
				} else {
					print -0.15/$stretch_y;
				}
				print " center\n";
			}
		}
		my $X_label_pos_y = -0.5/$stretch_y;
		$X_label_pos_y = 1 + 0.4/$stretch_y if defined($opt_P);
		my $X_label_pos_x = 0.5;
		$X_label_pos_x = 0.25 if (defined($opt_P) && ($sets != 1));
		print "set label $X_label_buckets at graph $X_label_pos_x,$X_label_pos_y center\n";
	}
	# X tics and title in seconds
	if ($opt_V && defined($opt_M) && (($s == $sets - 1 && !defined($opt_P)) || (!$s && defined($opt_P)))) {
		for (my $i = 5 * $opt_R; $i <= $max_x; $i += (5 * $opt_R)) {
			# skip the last tic if it may overlap with the legend
			if (($i > $min_x) && (($i < $max_x - 4) || defined($opt_P) || ($sets == 1 && !$opt_W))) {
				$digits = ((1.0 + 2.0**(1.0/$opt_R))/2.0 * (2**($i/$opt_R))) / ($opt_M * (10 ** 9));
				my $unit = "s";
				while ($digits < 1) {
					if ($unit eq "s") {
						$unit = "ms";
					} elsif ($unit eq "ms") {
						$unit = "{/Symbol=14 \155}s";	   #microseconds
					} elsif ($unit eq "{/Symbol=14 \155}s") {
						$unit = "ns";
					} else {
						print "ERROR: reached $digits $unit";
						exit 1;
					}
					$digits *= 1000;
				}
				printf "set label \'%d%s\' at graph %f,", $digits, $unit, ($i - $min_x)/($max_x - $min_x + 2.0);
				if (defined($opt_P)) {
					print -0.15/$stretch_y;
				} else {
					print 1 + 0.15/$stretch_y;
				}
				print " center\n";
			}
		}
		print "set label \'Average bucket latency\' at graph 0.5,", -0.5/$stretch_y, " center\n" if defined($opt_P);
	}
	
	print $CUSTOM_CMD[$s],"\n";
	
	print "plot '-' t '> 100 Operations' with boxxy fill pattern 3, '-' t '11-100 Operations' with boxxy fill pattern 2 border 1 linetype 1, '-' t '1-10 Operations' with boxxy fill pattern 5 border 1 linetype 1\n";
	
	for (my $ll = 0; $ll < $max_y; $ll++) {
	    for (my $i = 0; $i < $max_x; $i++) {
		    if ($BUCKETS[$s][$ll][$i] > 100.0) {
			    print $i + $min_x," ", $ll*2.0*$halfbox, " 0.5 $halfbox\n";
		    }
	    }
	}
	print "0.0 0.0 0.0 0.0\ne\n";
	
	for (my $ll = 0; $ll < $max_y; $ll++) {
	    for (my $i = 0; $i < $max_x; $i++) {
		    if ($BUCKETS[$s][$ll][$i] <= 100.0 && $BUCKETS[$s][$ll][$i] > 10.0) {
			    print $i + $min_x," ", $ll*2.0*$halfbox, " 0.5 $halfbox\n";
		    }
	    }
	}
	print "0.0 0.0 0.0 0.0\ne\n";
	
	for (my $ll = 0; $ll < $max_y; $ll++) {
	    for (my $i = 0; $i < $max_x; $i++) {
		    if ($BUCKETS[$s][$ll][$i] <= 10.0 && $BUCKETS[$s][$ll][$i] > 0.0) {
			    print $i + $min_x," ", $ll*2.0*$halfbox, " 0.5 $halfbox\n";
		    }
	    }
	}
	print "0.0 0.0 0.0 0.0\ne\n";
	print "unset label\n";
};

print "set nomultiplot; set out; set term pop\n";
